﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using Kinban.Contracts;
using Kinban.ViewModels;
using Kinect.KinectMouseControl;
using System.Diagnostics;

namespace Kinban
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, IGetStoryUnderMouse
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        AdornerDragDrop adorner = null;
        ListBox dragSource = null;

        //event handler for the mouse down of the listbox. This will start the drag drop operation
        private void MouseDownHandler(object sender, MouseButtonEventArgs e)
        {
            Debug.WriteLine("MouseDownHandler");
            ListBox parent = GetParent("ListBox", (FrameworkElement)sender) as ListBox;
            //set the drag source so that we can easily remove the item once the item is dropped on another listbox
            dragSource = parent;

            UIElement dataContainer;
            //get the object source for the selected item
            object data = GetObjectDataFromPoint(parent, e.GetPosition(parent), out dataContainer);

            //if the data is not null then start the drag drop operation
            if (data != null)
            {
                RemoveAdorner();//clear the adorner layer from previous adorners

                //create a new adorner for the item and add it to the Adorner Layer
                adorner = new AdornerDragDrop(QueueGrid, dataContainer);
                AdornerLayer.GetAdornerLayer(QueueGrid).Add(adorner);
                //do the drag drop operation and pass the data
                DragDrop.DoDragDrop(parent, data, DragDropEffects.Move);
            }
        }


        private Story GetDragStory(DragEventArgs e)
        {
            Story story = e.Data.GetData(typeof(Story)) as Story;
            return story;
        }

        private bool CanDrop(object sender, DragEventArgs e)
        {
            Story story = GetDragStory(e);

            if (story != null)
            {
                KanbanQueue destinationQueue = GetDestinationQueue(sender, e);
                KanbanQueue sourceQueue = GetSourceQueue(sender, e);

                if (sourceQueue != null && destinationQueue != null)
                {
                    if (destinationQueue.CanAcceptState(story.State))
                    {
                        return true;
                    }
                }
            }

            User person = e.Data.GetData(typeof(User)) as User;

            if (person != null)
            {
                Border parent = GetParent("Border", (FrameworkElement)sender) as Border;

                if (parent != null)
                {
                    var assignToStory = parent.DataContext as Story;
                    if (assignToStory != null)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        private KanbanQueue GetSourceQueue(object sender, DragEventArgs e)
        {
            var sourceQueue = (dragSource.DataContext) as KanbanQueue;
            return sourceQueue;
        }

        private KanbanQueue GetDestinationQueue(object sender, DragEventArgs e)
        {
            ListBox dragDestination = GetParent("ListBox", (FrameworkElement)sender) as ListBox;

            if (dragDestination == null)
            {
                return null;
            }

            if (dragDestination.Equals(dragSource))
            {
                // same list, nothing to do.
                return null;
            }

            return dragDestination.DataContext as KanbanQueue;
        }

        //update the _position of the adorner element
        private void DragOverHandler(object sender, DragEventArgs e)
        {
            //Debug.WriteLine("DragOverHandler");
            var canDrop = CanDrop(sender, e);
            adorner.UpdatePosition(e.GetPosition(QueueGrid), canDrop);
            if (canDrop)
            {
                e.Handled = true;
            }
        }

        private void GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            Debug.WriteLine("GiveFeedback");
            e.UseDefaultCursors = false;
            e.Handled = true;
        }

        //event handler for the drop event of the listbox
        private void DropHandler(object sender, DragEventArgs e)
        {
            Debug.WriteLine("DropHandler");
            try
            {
                if (!CanDrop(sender, e))
                {
                    return;
                }

                Story story = GetDragStory(e);

                if (story != null)
                {
                    KanbanQueue destinationQueue = GetDestinationQueue(sender, e);
                    KanbanQueue sourceQueue = GetSourceQueue(sender, e);

                    if (sourceQueue != null && destinationQueue != null)
                    {
                        //remove the object from the source
                        sourceQueue.Stories.Remove(story);

                        //add it to the new parent
                        destinationQueue.Stories.Add(story);
                        destinationQueue.StoriesView.Refresh();

                        return;
                    }
                }

                User person = e.Data.GetData(typeof(User)) as User;

                if (person != null)
                {
                    Border parent = GetParent("Border", (FrameworkElement)sender) as Border;

                    if (parent != null)
                    {
                        var assignToStory = parent.DataContext as Story;
                        if (assignToStory != null)
                        {
                            assignToStory.AssignedTo = person.TfsName;
                        }
                    }

                    return;
                }
            }
            finally
            {
                RemoveAdorner();
            }
        }

        private FrameworkElement GetParent(string searchForType, FrameworkElement sender)
        {
            var senderTypeName = sender.GetType().Name;


            if (senderTypeName == searchForType)
            {
                return sender;
            }

            if (sender.Parent != null)
            {
                return GetParent(searchForType, (FrameworkElement)(sender.Parent));
            }

            if (sender.TemplatedParent != null)
            {
                return GetParent(searchForType, (FrameworkElement)(sender.TemplatedParent));
            }

            return null;
        }

        #region Helpers
        //gets the object for the element selected (from the point) in the listbox (source)
        private static object GetObjectDataFromPoint(ListBox source, Point point, out UIElement dataContainer)
        {
            dataContainer = null;
            UIElement element = source.InputHitTest(point) as UIElement;
            if (element != null)
            {
                //get the object from the element
                object data = DependencyProperty.UnsetValue;
                while (data == DependencyProperty.UnsetValue)
                {
                    // try to get the object value for the corresponding element
                    data = source.ItemContainerGenerator.ItemFromContainer(element);

                    //get the parent and we will iterate again
                    if (data == DependencyProperty.UnsetValue)
                        element = VisualTreeHelper.GetParent(element) as UIElement;

                    //if we reach the actual listbox then we must break to avoid an infinite loop
                    if (element == source)
                        return null;
                }

                //return the data that we fetched only if it is not Unset value, which would mean that we did not find the data
                if (data != DependencyProperty.UnsetValue)
                {
                    dataContainer = element;
                    return data;
                }
            }

            return null;
        }

        //remove the adorner from the layer
        private void RemoveAdorner()
        {
            if (adorner != null)
                //remove the adorner
                AdornerLayer.GetAdornerLayer(QueueGrid).Remove(adorner);
        }

        #endregion

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var rootControl = (FrameworkElement)(this.Content);
            MainViewModel viewModel = (MainViewModel)rootControl.DataContext;
            if (viewModel != null)
            {
                System.Threading.Tasks.Task.Factory.StartNew(viewModel.Initialize);
                //viewModel.TfsViewModel.GetStoryUnderMouse = this;
            }
        }

        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            var rootControl = (FrameworkElement)(this.Content);
            IInitializable viewModel = (IInitializable)rootControl.DataContext;
            if (viewModel != null)
            {
                viewModel.Dispose();
            }
        }

        public Story GetStory()
        {
            //var point = Mouse.GetPosition(this);
            //var result =   VisualTreeHelper.HitTest( this, point);
            //throw new NotImplementedException();
            return null;
        }

        private void border_MouseEnter(object sender, MouseEventArgs e)
        {
            var mainViewModel = MainTab.DataContext as MainViewModel;
            mainViewModel.TfsViewModel.SelectedStory = ((FrameworkElement)sender).DataContext as Story;
        }

        private void border_MouseLeave(object sender, MouseEventArgs e)
        {
            var mainViewModel = MainTab.DataContext as MainViewModel;
            mainViewModel.TfsViewModel.SelectedStory = null;
        }

        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.LockUnlockCtrl.Text == "Lock")
            {
                this.PeopleList.IsEnabled = false;
                this.QueueGrid.IsEnabled = false;
                this.LockUnlockCtrl.Text = "UnLock";
            }
            else
            {
                this.PeopleList.IsEnabled = true;
                this.QueueGrid.IsEnabled = true;
                this.LockUnlockCtrl.Text = "Lock";
            }
        }
    }
}
